package main

import (
	"database/sql"
	"net/http"

	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
)

type App struct {
	Storage      MemoryStorage
	Router       *gin.Engine
	MySQLStorage MySQLStorage
}

func NewApp() *App {
	storage := MemoryStorage{albums: albums}
	router := gin.Default()
	mySQLStorage := NewMySQLStorage()
	app := &App{Router: router, Storage: storage, MySQLStorage: mySQLStorage}
	app.Routes()
	return app
}

func (app *App) GetAlbums(c *gin.Context) {
	rows, err := app.MySQLStorage.db.Query("SELECT id, title, artist, price FROM albums")
	if err != nil {
		c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	defer rows.Close()

	var albums []Album
	for rows.Next() {
		var a Album
		err := rows.Scan(&a.ID, &a.Title, &a.Artist, &a.Price)
		if err != nil {
			c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		albums = append(albums, a)
	}

	if err = rows.Err(); err != nil {
		c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.IndentedJSON(http.StatusOK, albums)
}

func (app *App) GetAlbumByID(c *gin.Context) {
	id := c.Param("id")

	row := app.MySQLStorage.db.QueryRow("SELECT id, title, artist, price FROM albums WHERE id = $1", id)

	var a Album
	err := row.Scan(&a.ID, &a.Title, &a.Artist, &a.Price)
	if err != nil {
		if err == sql.ErrNoRows {
			c.IndentedJSON(http.StatusNotFound, gin.H{"error": "Album not found"})
			return
		}
		c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.IndentedJSON(http.StatusOK, a)
}

func (app *App) CreateAlbum(c *gin.Context) {
	var newAlbum Album

	// Bind the request body to the newAlbum struct
	if err := c.BindJSON(&newAlbum); err != nil {
		c.IndentedJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Insert the new album into the database
	query := "INSERT INTO albums (title, artist, price) VALUES ($1, $2, $3) RETURNING id"
	err := app.MySQLStorage.db.QueryRow(query, newAlbum.Title, newAlbum.Artist, newAlbum.Price).Scan(&newAlbum.ID)
	if err != nil {
		c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.IndentedJSON(http.StatusCreated, newAlbum)
}
func (app *App) UpdateAlbum(c *gin.Context) {
	id := c.Param("id")

	var updatedAlbum Album

	// Bind the request body to the updatedAlbum struct
	if err := c.BindJSON(&updatedAlbum); err != nil {
		c.IndentedJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Update the album in the database
	query := "UPDATE albums SET title = $1, artist = $2, price = $3 WHERE id = $4"
	_, err := app.MySQLStorage.db.Exec(query, updatedAlbum.Title, updatedAlbum.Artist, updatedAlbum.Price, id)
	if err != nil {
		c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	updatedAlbum.ID = id
	c.IndentedJSON(http.StatusOK, updatedAlbum)
}

func (app *App) DeleteAlbum(c *gin.Context) {
	id := c.Param("id")

	// Delete the album from the database
	query := "DELETE FROM albums WHERE id = $1"
	_, err := app.MySQLStorage.db.Exec(query, id)
	if err != nil {
		c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.IndentedJSON(http.StatusOK, gin.H{"message": "Album deleted successfully"})
}

func (app *App) Routes() {
	app.Router.GET("/albums", app.GetAlbums)
	app.Router.GET("/albums/:id", app.GetAlbumByID)
	app.Router.POST("/albums", app.CreateAlbum)
	app.Router.PUT("/albums/:id", app.UpdateAlbum)
	app.Router.DELETE("/albums/:id", app.DeleteAlbum)
}

func main() {
	app := NewApp()
	app.Router.Run("localhost:8080") // Запуск сервера
}
